#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <vector>

class Counter {
private:
    int value;

    std::atomic_int value_a;
public:

    Counter() : value(0), value_a(0) {

    }

    int get() {
        return value;
    }

    int get_a() {
        return value_a.load();
    }

    int increment_atomic() {
        int v = value_a.load();
        while (!value_a.compare_exchange_weak(v, v + 1));
        return value_a.load();
    }

    int increment() {
        return value++;
    }

};

void add_func(bool atomic, Counter &count, std::mutex &mtx, std::condition_variable &cv) {
    {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock);
    }
    if (atomic) {
        for (int i = 0; i < 1000; i++)
            count.increment_atomic();
    } else {
        for (int i = 0; i < 1000; i++)
            count.increment();
    }

}

int main(int argc, char** argv) {

    std::vector<std::thread*> threads;
    std::mutex mtx;
    std::condition_variable cv;
    Counter cnt;

    for (int i = 0; i < 1000; i++)
        threads.push_back(new std::thread(add_func, true, std::ref(cnt), std::ref(mtx), std::ref(cv)));

    {
        std::cout << "Press any key" << std::endl;
        std::cin.get();
        std::unique_lock<std::mutex> lock(mtx);
        cv.notify_all();
    }

    for (auto a : threads) a->join();
    std::cout << "Normal: " << cnt.get() << std::endl;
    std::cout << "Atomic: " << cnt.get_a() << std::endl;
    return 0;
}

